M1 Macで作る、ファミコンソフトプログラミング。 アセンブラでハローワールド編
2021.11.08
この記事は最終更新日から1年以上が経過しています。
どもです。
前回のこちらの記事に引き続きファミコンプログラミングでもと。
前回は、NES研究所さんのサンプルを動かして「HELLO WORLD」を表示させたのですが、今回は実際にアセンブラでプログラムを書いて作って行こうかと思います。
やりたいこととしては、前回同様に「HELLO WORLD」の文字を画面に出したい。
そんなの、「HELLO WORLD」の文字列を出すだけなら簡単でしょ。
と思いそうですが、昔々のがファミコン時代の頃には文字列というのもなく、端的に言うと文字を出すのも画像(スプライト)を作る必要がある訳なのです。
では、M1 Macの環境でファミコンゲームの作成を行って行きましょう。
環境
- Mac mini (M1, 2020)
- Mac OS 11.6
- Apple clang version 13.0.0
スプライト画像作成
という訳で、スプライト画像の作成から行って行くのですが、それには「YYCHR」というツールを用いて作成していきます。
YYCHR – ダウンロード
こちら、Windows用のアプリとなりますので、前回の「M1 (Appleシリコン)Macで Widowsアプリを起動」の記事で紹介したように、CrossOver Wineをインストールしそちらで起動します。
$ wine64 YYCHR.exe
起動すると、この様な表示になるかと思います。

今回は、「YYCHR」の使い方詳細は割愛させていただきます。
いつか機会があれば書いていきたいとは思いますが、こちらのYYCHRのWikiに使用方法など書かれているので、そちらを使用方法は確認していただけると理解できるかと思います。
ABC…とアルファベットのスプライトを作って行くのですが、こちらの書籍など参考にすると作成がスムーズに進みますので、レトロゲーム作成される方は、1冊持っておくのをオススメします!
という事で、上記の書籍を参考に以下の様にスプライトの作成。

作成したスプライトは、character.chrファイルとして書き出しを行います。
アセンブラでプログラミング
先程、「YYCHR」で作成したスプライトのcharacter.chrファイルを読み込み、「HELLO WORLD」と表示される様に、hello.asmファイルのアセンブラプログラムを作成します。
作成するアセンブラプログラムは以下の様な感じです。
hello.asm
;---- iNES Header
.inesprg 1 ; PRG 16KB
.ineschr 1 ; CHR 8KB
.inesmap 0 ; Mapper 0
.inesmir 0 ; horizontal mirroring
;---- bank0
.bank 0
.org $C000
RESET:
sei
cld
.vblankWait1
bit $2002
bpl .vblankWait1
.vblankWait2
bit $2002
bpl .vblankWait2
; reset PPU status
lda $2002
lda #$3F
sta $2006
lda #$00
sta $2006
; X register initialization
ldx #0
.loadBgPalette
lda bgPalette, x
sta $2007
inx
cpx #16
bne .loadBgPalette
; reset PPU status
lda $2002
lda #$3F
sta $2006
lda #$10
sta $2006
; X register initialization
ldx #0
.loadSpritePalette
lda spritePalette, x
sta $2007
inx
cpx #16
bne .loadSpritePalette
; H
lda #$50
sta $0200
lda #$07
sta $0201
lda #%00000001
sta $0202
lda #$10
sta $0203
; E
lda #$50
sta $0204
lda #$04
sta $0205
lda #%00000011
sta $0206
lda #$18
sta $0207
; L
lda #$50
sta $0208
lda #$0B
sta $0209
lda #%00000011
sta $020A
lda #$1F
sta $020B
; L
lda #$50
sta $020C
lda #$0B
sta $020D
lda #%00000011
sta $020E
lda #$26
sta $020F
; O
lda #$50
sta $0210
lda #$0E
sta $0211
lda #%00000011
sta $0212
lda #$2D
sta $0213
; W
lda #$50
sta $0214
lda #$16
sta $0215
lda #%00000011
sta $0216
lda #$37
sta $0217
; O
lda #$50
sta $0218
lda #$0E
sta $0219
lda #%00000011
sta $021A
lda #$3F
sta $021B
; R
lda #$50
sta $021C
lda #$11
sta $021D
lda #%00000011
sta $021E
lda #$46
sta $021F
; L
lda #$50
sta $0220
lda #$0B
sta $0221
lda #%00000011
sta $0222
lda #$4D
sta $0223
; D
lda #$50
sta $0224
lda #$03
sta $0225
lda #%00000011
sta $0226
lda #$54
sta $0227
; NMI
lda #%10000000
sta $2000
lda #%00010000
sta $2001
.forever
jmp .forever
NMI:
lda #$00
sta $2003
lda #$02
sta $4014
rti
IRQ:
rti
spritePalette:
.byte $0D, $01, $05, $20
.byte $0D, $01, $05, $20
.byte $0D, $01, $05, $20
.byte $0D, $01, $05, $20
bgPalette:
.byte $01, $32, $36, $3A
.byte $01, $22, $26, $2A
.byte $01, $12, $16, $1A
.byte $01, $02, $06, $0A
;---- bank1
.bank 1
.org $FFFA
.word NMI
.word RESET
.word IRQ
;---- bank2 (CHR bank0)
.bank 2
.org $0000
.incbin "character.chr"
色々書かれていますが、全部説明となると途方もないので、とりあえず、bank2に先程作成したスプライトのcharacter.chrを読み込んで、.loadSpritePaletteでスプライトの種類、位置を設定して画面に配置しております。
それでは、上記のアセンブラプログラムを元に、ファミコン実行ファイル「.nes」形式にアセンブルするために「nesasm」をインストールしていきます。
nesasm インストール
NES 6502 assemblyをアセンブルするため「nesasm」をインストールしていきます。「nesasm」のソースはgithubに上がっております。
nesasm
https://github.com/camsaul/nesasm
zipファイルをダウンロードを行うか、git clone行うかしローカルにファイルをダウンロードします。
以下のコマンドを実行nesasmをインストールします。
$ cd source && make && sudo make install
インストール完了後、nesasmコマンド実行し、以下の様に表示すれば問題なくインストール完了です。
nesasm NES Assembler (v3.1) nesasm [-options] [-? (for help)] infile -s/S : show segment usage -l # : listing file output level (0-3) -m : force macro expansion in listing -raw : prevent adding a ROM header -srec : create a Motorola S-record file infile : file to be assembled
先程の作成したスプライトのcharacter.chrファイルと、hello.asmが置かれたディレクトリにて以下のコマンドを実行します。
$ nesasm hello.asm
すると、新しく「hello.fns」と「hello.nes」ファイルが生成されます。

「hello.nes」ファイルが実行ファイルとなりますので、エミュレーターを使ってデバッグしてみましょう。
シミュレータでデバッグ
ファミコンシミュレータは沢山存在します。
とりあえず、開発用として重宝されている有名な「fceux」でデバッグを行うと。
fceux

おお。問題なく表示されていますね。
続いて、「Open Emu」でデバッグしてみると。
Open Emu

おや、「LD」の2文字が表示されません。。
バグか。。と思われがちですが、ファミコンの仕様としてはこちらが正解。
スプライトは、同時に8個以上並べられない仕様なのです。8個以上並べると表示されなくなります。
Open Emuのコアは、FCE Ultraぽいので、こちらのほうが仕様に沿っていて、FCE Ultraからフォークされて拡張された「fceux」では仕様通りではないって感じでしょうか。(検証してみた感想)
という訳で、仕様に沿って文字表示されたいとなると、Wからの文字をずらしたりすると良いでしょうか。
Wから Y座標を10ずらしてみます。
; W
lda #$60
....
すると、以下の様に全てのスプライトが表示され「HELLO WORLD」と認識できました。

この手法はなにか見覚えありますね。
そう、チャレンジャーのゲーム中によく出てくる文字表示の表現だ!

仕様に沿って、8個以上文字が並ばないように、少しずつずらして、文字を表示されているのがわかりますね。


当時はおしゃれでやっているのかと思っておりましたが、そういった理由があったのですね。
終わり
と、ざっくり書いてきましたが、アセンブラでプログラムを作成すると辛いことが確認できましたので(そりゃそうだ 笑)、現在では C言語などでも作成できるようになっておりますので、今後は開発する際はそちらでやって行こうかなとか思っております。
ただ、やることいっぱいなので、後になっていくのだろうなぁと思っております。。。
ではでは。またまた。




















